#include <am.h>
#include <riscv/riscv.h>
#include <klib.h>

static Context* (*user_handler)(Event, Context*) = NULL;

Context* __am_irq_handle(Context *c) {
  if (user_handler) {
    Event ev = {0};
    switch (c->mcause) {
      case MCAUSE_ECALL_M: 
        if(c->GPR1 == -1) ev.event = EVENT_YIELD;
        else ev.event = EVENT_SYSCALL; 
        c->mepc += 4;
        break;
      case MCAUSE_TIM_INT_M:
        ev.event = EVENT_IRQ_TIMER;
        //c->mepc += 4;
        volatile uint64_t *mtimecmp = (uint64_t*)(0x02004000);
        *mtimecmp+= 10000;
        asm volatile("csrc mip, %0" : : "r"(MIP_MTIP_MASK|MIP_MSIP_MASK));
        break;
      default: ev.event = EVENT_ERROR; break;
    }

    c = user_handler(ev, c);
    assert(c != NULL);
  }

  return c;
}

extern void __am_asm_trap(void);

bool cte_init(Context*(*handler)(Event, Context*)) {
  // initialize exception entry
  asm volatile("csrw mtvec, %0" : : "r"(__am_asm_trap));

  // register event handler
  user_handler = handler;

  return true;
}

Context *kcontext(Area kstack, void (*entry)(void *), void *arg) {
  Context *c = (Context*)(kstack.end - sizeof(Context));
  uint64_t *p = (uint64_t *)c;
  for (size_t i = 0; i < sizeof(Context)/sizeof(uint64_t); i++)
  {
    p[i] = i;
  }
  c->mepc = (uintptr_t)entry;
  c->mstatus = 0xa00001880;
  c->gpr[10] = (uintptr_t)arg;

  
  return c;
}

void yield() {
  asm volatile("li a7, -1; ecall");
}

bool ienabled() {
  uint64_t mie,mstatus;
  asm volatile("csrr %0,mstatus"  : "=r"(mstatus));
  asm volatile("csrr %0,mie" :  "=r"(mie));
  if((mie&MIE_MTIE_MASK)&&(mstatus&MSTATUS_MIE_MASK)) return true;
  return false;
}
void iset(bool enable) {
  if(enable)
  {
    asm volatile("csrs mie, %0" : : "r"(MIE_MTIE_MASK));
    asm volatile("csrs mstatus, %0" : : "r"(MSTATUS_MIE_MASK));
  } else
  {
    asm volatile("csrc mstatus, %0" : : "r"(MSTATUS_MIE_MASK));
    asm volatile("csrc mie, %0" : : "r"(MIE_MTIE_MASK));
  }

}
